#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
@Project : POS_api_test_project 
@File    : caseAutomaticControl.py
@IDE     : PyCharm 
@Author  : Mario
@Date    : 2022/5/26 15:27 
@Describe: pytest用例自动生成
"""
import os
from Config.setting import ConfigHandler
from Utils.readFilesUtils.yamlControl import GetYamlData
from Utils.readFilesUtils.get_all_files_path import get_all_files
from Utils.readFilesUtils.testcase_template import write_testcase_file


class TestCaseAutomaticGeneration:
    """自动生成自动化测试中的test_case代码"""

    def __init__(self):
        pass

    @classmethod
    def case_data_path(cls) -> str:
        """
        获取yaml用例文件路径
        :return: 返回yaml用例文件路径
        """
        return ConfigHandler.TEST_CASE_DATA_PATH

    @classmethod
    def case_path(cls) -> str:
        """
        获取测试用例代码存放路径
        :return: 返回测试用例代码文件路径
        """
        return ConfigHandler.TEST_CASE_PATH

    def file_name(self, file: str) -> str:
        """
        通过 yaml文件的命名，将名称转换成 py文件的名称
        :param file: yaml 文件路径
        :return: 示例: UserInfo.py
        """
        case_data_path_len = len(self.case_data_path())  # 获取yaml文件存放路径长度
        yaml_path = file[case_data_path_len:]  # 根据yaml存放路径长度进行字符串截取用例路径
        file_name = None
        if '.yaml' in yaml_path:  # 判断yaml_path是否为.yaml格式
            file_name = yaml_path.replace('.yaml', '.py')  # 把.yaml格式文件替换为.py文件
        elif '.yml' in yaml_path:
            file_name = yaml_path.replace('.yaml', '.py')
        return file_name

    def get_case_path(self, file_path: str) -> tuple:
        """
        根据 yaml 中的用例，生成对应 test_case 层代码的路径
        :param file_path: yaml用例路径
        :return: ('D:\\Project\\pos_api_pytest_project\\test_case\\Login\\login.py', 'login.py')
        """
        # 这里通过"\\" 符号进行分割，提取出来文件名称
        path = self.file_name(file_path).split(os.sep)
        # 通过replace方法给用例文件加个"test_"前缀
        case_name = path[-1] = path[-1].replace(path[-1], "test_" + path[-1])
        new_name = os.sep.join(path)
        return ConfigHandler.TEST_CASE_PATH + new_name, case_name

    def get_test_class_title(self, file_path: str) -> str:
        """
        自动生成类名称
        :param file_path: yaml用例路径
        :return:
        """
        # 提取文件名称
        _FILE_NAME = os.path.split(self.file_name(file_path))[1][:-3]
        _NAME = _FILE_NAME.split("_")
        # 将文件名称格式，转换成类名称: sup_apply_list --> SupApplyList
        for i in range(len(_NAME)):
            _NAME[i] = _NAME[i].capitalize()
        _CLASS_NAME = "".join(_NAME)
        return _CLASS_NAME

    @classmethod
    def error_message(cls, param_name, file_path):
        """
        用例中填写不正确的相关提示
        :return:错误信息
        """
        message = '用例中未找到{}参数值,请检查新增的用例中是否填写对应的参数内容,如果已经填写可能是yaml参数缩进不正确~用例路径:{}'.format(param_name, file_path)
        return message

    def func_title(self, file_path: str) -> str:
        """
        自动生成函数名称
        :param file_path: yaml用例路径
        :return:
        """
        _FILE_NAME = os.path.split(self.file_name(file_path))[1][:-3]
        return _FILE_NAME

    @classmethod
    def allure_epic(cls, case_data: dict, file_path: str) -> str:
        """
        用于 allure 报告装饰器中的内容 @allure.epic("项目名称")
        :param case_data: 用例数据
        :param file_path: 用例路径
        :return: YAML文件allureEpic结果
        """
        try:
            return case_data['case_common']['allureEpic']
        except KeyError:
            raise KeyError(cls.error_message('allureEpic', file_path))

    @classmethod
    def allure_feature(cls, case_data: dict, file_path: str) -> str:
        """
        用于 allure 报告装饰器中的内容 @allure.feature("模块名称")
        :param case_data: 用例数据
        :param file_path: 用例路径
        :return: YAML文件allureFeature结果
        """
        try:
            return case_data['case_common']['allureFeature']
        except KeyError:
            raise KeyError(cls.error_message('allureFeature', file_path))

    @classmethod
    def allure_story(cls, case_data: dict, file_path: str) -> str:
        """
        用于 allure 报告装饰器中的内容  @allure.story("测试功能")
        :param case_data: 用例数据
        :param file_path: 用例路径
        :return: YAML文件allureStory结果
        """
        try:
            return case_data['case_common']['allureStory']
        except KeyError:
            raise KeyError(cls.error_message('allureStory', file_path))

    def make_dir(self, file_path: str) -> None:
        """ 判断生成自动化代码的文件夹路径是否存在，如果不存在，则自动创建 """
        _CASE_DIR_PATH = os.path.split(self.get_case_path(file_path)[0])[0]
        if not os.path.exists(_CASE_DIR_PATH):
            os.makedirs(_CASE_DIR_PATH)

    def yaml_path(self, file_path: str) -> str:
        """
        生成动态 yaml 路径, 主要处理业务分层场景
        :param file_path: 如业务有多个层级, 则获取到每一层/test_demo/DateDemo.py
        :return: Login/common.yaml
        """
        i = len(self.case_data_path())
        # 兼容 linux 和 window 操作路径
        yaml_path = file_path[i:].replace("\\", "/")
        return yaml_path

    def get_case_automatic(self) -> None:
        """ 自动生成pytest测试代码"""
        # 获取所有Data目录下的所有yaml文件
        file_path = get_all_files(file_path=ConfigHandler.TEST_CASE_DATA_PATH, yaml_data_switch=True)
        for file in file_path:
            # 判断代理拦截的yaml文件，不生成test_case代码
            if 'proxy_data.yaml' not in file:
                # 判断用例需要用的文件夹路径是否存在，不存在则创建
                self.make_dir(file)
                yaml_case_process = GetYamlData(file).get_yaml_data()
                write_testcase_file(
                    allure_epic=self.allure_epic(case_data=yaml_case_process, file_path=file),
                    allure_feature=self.allure_feature(yaml_case_process, file_path=file),
                    class_title=self.get_test_class_title(file), func_title=self.func_title(file),
                    case_path=self.get_case_path(file)[0], yaml_path=self.yaml_path(file),
                    file_name=self.get_case_path(file)[1],
                    allure_story=self.allure_story(case_data=yaml_case_process, file_path=file)
                )


if __name__ == '__main__':
    TestCaseAutomaticGeneration().get_case_automatic()
